<?php
/*
 *  Jiba: A small collection of classes to make php easier.
 *  Copyright (C) 2007  Dimitri Michaux <dimitri.michaux@gmail.com>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * db.class.php, Jiba
 * 
 * A powerfull database access class that eliminates the need to write those
 * anoying queries. Now you can focus all your energy on your code.
 *
 * @author Dimitri Michaux
 * @version 0.1
 * @package jiba
 */

class DB
{
    /**
     * MySQL database handler
     *
     * @var     string
     * @access  private
     */
    private $_dbh;
    
    /**
     * Returns a reference to the database object, if no object
     * exists a new object and connection is created
     *
     * You cannot create a database object like this: $db = new DB
     * You must use this function!
     */
    public static function &get()
    {
      static $db = null;
      
      if( $db == null )
        $db = new DB;
      
      return $db;
    }
    
    /**
     * DB constructur function:
     * connects to the server and selects a database
     * if the connection has failed the script will treminate
     *
     * @access   private
     */
    private function __construct()
    {
        if ( !$this->_dbh = @mysql_connect(_DB_HOST,_DB_USER,_DB_PASS) )
        {
            $this->_printError( "<b>Error establishing a database connection!</b>" );
            exit;
        }

        //select the database
        if ( !@mysql_select_db(_DB_NAME,$this->_dbh))
		{
			$this->_printError( "<b>Error selecting database <u>"._DB_NAME."</u>!</b>");
                        exit;
		}
		
        return true;
    }
    
    /**
     * Prints an error message
     *
     * @param   string  $str    The error message to display
     * @return  void
     * @access  private
     */
    private function _printError($str = "")
    {
	global $_ERR;
        
        if ( $str=="" ) $str = mysql_error();
        
        echo $str;
    }
    
    /**
     * Executes a MySQL query just like mysql_query()
     * The script will terminate on an error
     *
     * @param   string  $query a valid MySQL query
     * @return  mixed   the same values as mysql_query()
     * @access  public
     */
    private function query( $query="" )
    {
    	//echo $query."<br/>";
        if( $query!="" )
        {
            $result = mysql_query( $query, $this->_dbh );
            
            if( !$result )
            {
                $this->_printError( "There is an error in the following MySQL query: $query" );
                exit;
            }
        }
        else
        {
            $this->_printError( "You're trying to execute an empty query." );
            exit;
        }
        return $result;
    }
    
   /**
    * Returns the contents of one cell from a MySQL result set
    *
    * @param    object      $recordset      The recordset to operate on
    * @param    int         $row            row to get data from
    * @param    string      $field          field to return
    * @return   (depends on field content)
    *
    */
    private function result($recordset,$row,$field=0)
    {
        if ( empty($recordset) )
            $this->_printError("Passed recordset isn't valid");
		
        return stripslashes( @mysql_result($recordset,$row,$field) );
    }
    
    /**
     * Transfroms a recordset into an array
     *
     * @param   object  $recordSet  The record set to operate on
     * @param   bool    $both       get both assoc and numeric indices
     * @return  array   Returns data array of current row from recordset
     * @access  public
     */
    private function fetchArray( $recordSet, $both=true )
    {
        $array = array();

        if( $both )
            $array = mysql_fetch_array( $recordSet, MYSQL_BOTH );
        else
            $array = mysql_fetch_array( $recordSet, MYSQL_ASSOC );
        
        if( $array===false )
            return false;
        else
        {
            foreach( $array as $key => $value )
                $array[$key] = stripslashes( $value );
        
            return $array;
        }
    }
    
    private function numRows( $recordSet )
    {
        return mysql_num_rows( $recordSet );
    }
    
    /**
     * Gets an item from the database (Slicker version of a Geeklog function)
     *
     * @param   string  $table      table to get the item from
     * @param   string  $what       fieldname
     * @param   string  $condition  MySQL WHERE clause !!!YOU SHOULD ESCAPE THIS YOURSELF!!!
     * @return  mixed   the saught value
     * @access  public
     */
    public function getItem( $table, $what, $condition="" )
    {
        if( empty($condition) )
            $result = $this->query( "SELECT " . mysql_real_escape_string($what) . " FROM $table" );
        else
            $result = $this->query( "SELECT " . mysql_real_escape_string($what) . " FROM $table WHERE $condition" );

        $item = $this->fetchArray( $result );
        
        if( count($item)==0 )
            return false;
        else
            return $item[0];
    }
    
    /**
     * Gets all the rows that match the condition and
     * returns them as an associative array
     *
     * exp: $data[row][column1][column2]..
     */
    public function getRows( $table, $condition=null, $orderBy=null, $asc=true, $limit=null, $offset=null )
    {
      if( $condition == null )
          $result = "SELECT * FROM $table";
      else
          $result = "SELECT * FROM $table WHERE $condition";
    
      if( $orderBy != null )
        $result.= " ORDER BY " . mysql_real_escape_string( $orderBy );
      
      if( $orderBy != null && $asc )
        $result.= " ASC";
      elseif( $orderBy != null && !$asc )
        $result.= " DESC";
      
      if( $limit != null && is_int($limit) && $offset != null && is_int($offset) )
        $result.= " LIMIT ". mysql_real_escape_string( $limit ).", ". mysql_real_escape_string( $offset );
      elseif( $limit != null && is_int($limit) )
        $result.= " LIMIT ". mysql_real_escape_string( $limit );
      
      $result = $this->query( $result );
      
      $i = 0;
      while( $row = $this->fetchArray($result,false) )
      { 
        foreach( $row as $key => $value )
          $items[$i][$key] = $value;

        $i++;
      }
      
      return $items;
    }
    
    /**
     * Deletes data from the database (From Geeklog)
     *
     * This will delete some data from the given table where id = value.  If
     * id and value are arrays then it will traverse the arrays setting
     * $id[curval] = $value[curval].
     *
     * @param    string          $table      Table to delete data from
     * @param    array|string    $id         field name(s) to include in where clause
     * @param    array|string    $value      field value(s) corresponding to field names
     * @return   boolean     Returns true on success otherwise false
     */
    public function delete( $table, $id, $value )
    {
        $sql = "DELETE FROM $table";

        if (is_array($id) || is_array($value)) {
            if (is_array($id) && is_array($value) && count($id) == count($value)) {
                // they are arrays, traverse them and build sql
                $sql .= ' WHERE ';
                for ($i = 1; $i <= count($id); $i++) {
                    if ($i == count($id)) {
                        $sql .= mysql_real_escape_string( current($id) ) . " = '" . mysql_real_escape_string( current($value) ) . "'";
                    } else {
                        $sql .= mysql_real_escape_string( current($id) ) . " = '" . mysql_real_escape_string( current($value) ) . "' AND ";
                    }
                    next($id);
                    next($value);
                }
            } else {
                // error, they both have to be arrays and of the
                // same size
                return false;
            }
        } else {
            // just regular string values, build sql
            if (!empty($id) && ( isset($value) || $value != "")) { 
                $sql .= " WHERE ".mysql_real_escape_string($id)." = '".mysql_real_escape_string($value)."'";
            }
        }

        $this->query($sql);
        
        return true;
    }
    
    /**
     * Save information in the database
     *
     * The data array should look like this:
     *      array( field_name1 => field_content1,
     *             filed_name2 => field_content2 )
     *
     * @param   string      $table      the table to save the data in
     * @param   array       $data       the data id's and values
     * @param   bool        $replace    use REPLACE INTO instead of INSERT INTO
     * @return  bool        true if it worked
     * @access  public
     */
    public function save( $table, $data, $replace=true )
    {
        //Get all the id's and corresponding data
        $fields = "";
        $values = "";
        $num    = count( $data );
        $i = 0;

        foreach( $data as $field => $value )
        {
            $i++;

            $fields.= mysql_real_escape_string( $field );
            $values.= "'" . mysql_real_escape_string( $value ) . "'";

            if( $i < $num ) //place comma's
            {
                $fields.= ",";
                $values.= ",";
            }
        }

        //Build and execute the MySQL query
        if( $replace )
            $sql = "REPLACE INTO ";
        else
            $sql = "INSERT INTO ";

        $sql.= $table . " ($fields) VALUES ($values)";

        return $this->query( $sql );
    }
    
    /**
     * Update a MySQL entry
     *
     * @param   string  $table      the table to update in
     * @param   array   $data       data to insert array( 'field_name' => 'field_data' );
     * @param   string  $condition  MySQL WHERE clause !!!YOU SHOULD ESCAPE THIS YOURSELF!!!
     * @return  bool    true if it worked
     * @access  public
     */
    public function update( $table, $data, $condition )
    {
        $sql = "UPDATE $table SET ";
        $num = count( $data );
        $i   = 0;
        
        foreach( $data as $field => $value )
        {
            $i++;

            $sql.= mysql_real_escape_string($field) . "='" . mysql_real_escape_string($value) . "'";
            
            if( $i < $num ) //place comma's
                $sql.= ",";
        }
        
        if( $condition=="" )
        {
            $this->_printError( "You need to give a condition for updating. MySQL query: $sql" );
            exit;
        }
        else
            $sql.= " WHERE $condition ";
            
        return $this->query( $sql );
    }
    
    /**
     * Returns the number of records for a query that meets the given criteria
     * (From Geeklog)
     *
     * This will build a SELECT count(*) statement with the given criteria and
     * return the result
     *
     * @param    string          $table  Table to perform count on
     * @param    array|string    $id     field name(s) of fields to use in where clause
     * @param    array|string    $value  Value(s) to use in where clause
     * @return   boolean     returns count on success otherwise false
     */
    public function count($table,$id='',$value='')
    {
        $sql = "SELECT COUNT(*) FROM $table";

        if (is_array($id) || is_array($value)) {
            if (is_array($id) && is_array($value) && count($id) == count($value)) {
                // they are arrays, traverse them and build sql
                $sql .= ' WHERE ';
                for ($i = 1; $i <= count($id); $i++) {
                    if ($i == count($id)) {
                        $sql.= mysql_real_escape_string(current($id)) . " = '" . mysql_real_escape_string(current($value)) . "'";
                    } else {
                        $sql.= mysql_real_escape_string(current($id))." = '".mysql_real_escape_string(current($value))."' AND ";
                    }
                    next($id);
                    next($value);
                }
            } else {
                // error, they both have to be arrays and of the
                // same size
                return false;
            }
        } else {
            if (!empty($id) && ( isset($value) || $value != "")) { 
                $sql .= " WHERE $id = '" . mysql_real_escape_string($value) . "'";
            }
        }

        $result = $this->query($sql);

        return ($this->result($result,0));
    }
    
    public function freeResult( $res )
    {
        return mysql_free_result( $res );
    }

    public function insertId()
    {
        return mysql_insert_id( $this->_dbh );
    }
}
?>